'use strict'
import { isSafari, isTrident } from './browser-util.ts'

/**
 * 格式化时长（ms）
 * @param value 时长
 * @param format 格式化的格式
 * @returns {TimestampModel}
 */
export const formatByTimestamp = (value = 0, format = 'hh:mm:ss.SSS') => {
	return new TimestampModel(value, format)
}

/**
 * 格式化时长（s）
 * @param value 时长
 * @param format 格式化的格式
 * @returns {TimeModel}
 */
export const formatByTime = (value = 0, format = 'hh:mm:ss.SSS') => {
	return new TimeModel(value, format)
}

/**
 * 格式化日期
 * @param value 日期或时间戳
 * @param format 格式化的格式
 * @returns {DateModel}
 */
export const formatByDate = (value = new Date(), format = 'yyyy-MM-dd HH:mm.ss.SSS') => {
	return new DateModel(value, format)
}

/**
 * 格式化日期
 * @param date
 * @param format 格式化的格式
 * @returns {DateModel}
 */
export const formatByString = (date: string, format = 'yyyy-MM-dd HH:mm.ss.SSS') => {
	const replaceDate = date.replace(/T/, ' ').replace(/-/g, '/')
	const value = new Date(replaceDate)
	return formatByDate(value, format)
}

/**
 * 本地日期格式化
 * @param dateTime
 * @param needSlash 是否需要斜杠
 */
export const formatSubDate = (dateTime: string | undefined, needSlash?: boolean): string => {
	return formatDateTimeWithSub(dateTime, 10, needSlash)
}

/**
 * 本地日期格式化
 * @param dateTime
 * @param needSlash 是否需要斜杠
 */
export const formatSubDateTime = (dateTime: string | undefined, needSlash?: boolean): string => {
	return formatDateTimeWithSub(dateTime, 16, needSlash)
}

/**
 * 本地日期格式化
 * @param dateTime
 * @param needSlash 是否需要斜杠
 * @param length
 */
export const formatDateTimeWithSub = (dateTime: string | undefined, length: number, needSlash?: boolean): string => {
	if (!dateTime) return ''
	dateTime = dateTime.replace('T', ' ')
	if (dateTime.length > length) {
		const date = dateTime.substring(0, length)
		return needSlash ? date.replace(/-/g, '/') : date
	} else {
		return dateTime
	}
}

/**
 * 格式化数字
 * @param number 数字
 * @param length 格式化后的长度
 * @returns {string} 字符串
 */
const text = (number = 0, length = 2) => (number + '').padStart(length, '0')

/**
 * 时间戳对象
 */
export class TimestampModel {
	private _text: string
	private _day: number
	private _hour: number
	private _minute: number
	private _second: number
	private _sss: number

	constructor(value = 0, format = 'hh:mm:ss.SSS') {
		this._text = ''
		this._day = 0
		this._hour = 0
		this._minute = 0
		this._second = 0
		this._sss = 0
		this._renderValue(value)
		this._format(format)
	}

	_renderValue(value = 0) {
		this._sss = value % 1000
		value = Number(Math.floor(value / 1000).toFixed(0))
		this._second = value % 60
		value = Number(Math.floor(value / 60).toFixed(0))
		this._minute = value % 60
		value = Number(Math.floor(value / 60).toFixed(0))
		this._hour = value % 24
		value = Number(Math.floor(value / 24).toFixed(0))
		this._day = value
	}

	_format(format = 'hh:mm:ss.SSS') {
		let tempText = this._day === 0 ? format.replace(/d+:?/gi, '') : format
		tempText = this._hour === 0 ? tempText.replace(/h+:?/gi, '') : tempText
		tempText = tempText.replace(/d+/gi, this._day.toString())
		tempText = tempText.replace(/h+/gi, /d/.test(format) ? text(this._hour) : text((this._day || 0) * 24 + this._hour))
		tempText = tempText.replace(/m+/gi, /h/.test(format) ? text(this._minute) : text((this._hour || 0) * 60 + this._minute))
		tempText = tempText.replace(/s+/g, text(this._second))
		tempText = tempText.replace(/S+/g, text(this._sss, 3))
		this._text = tempText
	}

	get sss(): number {
		return this._sss
	}

	get second(): number {
		return this._second
	}

	get minute(): number {
		return this._minute
	}

	get hour(): number {
		return this._hour
	}

	get day(): number {
		return this._day
	}

	get text(): string {
		return this._text
	}
}

/**
 * 时间对象
 */
export class TimeModel {
	public readonly text: string
	public readonly day: number
	public readonly hour: number
	public readonly minute: number
	public readonly second: number

	constructor(value = 0, format = 'hh:mm:ss') {
		const model = new TimestampModel(value * 1000, format)
		this.text = model.text
		this.day = model.day
		this.hour = model.hour
		this.minute = model.minute
		this.second = model.second
	}
}

/**
 * 日期对象
 */
export class DateModel {
	private _text: string
	private _year: number
	private _month: number
	private _day: number
	private _hour: number
	private _minute: number
	private _second: number
	private _sss: number
	private _week: number
	private _date: Date
	private _timestamp: number

	constructor(value = new Date(), format = 'yyyy-MM-dd HH:mm.ss.SSS') {
		this._year = 0
		this._month = 0
		this._day = 0
		this._hour = 0
		this._minute = 0
		this._second = 0
		this._sss = 0
		this._week = 0
		this._date = new Date()
		this._timestamp = this._date.getTime()
		this._text = ''
		this._renderValue(value)
		this._format(format)
	}

	_renderValue(value: Date | string = new Date()) {
		value = typeof value === 'string' && (isSafari() || isTrident()) ? value.replace(/-/g, '/') : value
		this._date = value instanceof Date ? value : new Date(value)
		this._year = this._date.getFullYear()
		this._month = this._date.getMonth() + 1
		this._day = this._date.getDate()
		this._hour = this._date.getHours()
		this._minute = this._date.getMinutes()
		this._second = this._date.getSeconds()
		this._sss = this._date.getMilliseconds()
		this._week = this._date.getDay()
		this._timestamp = this._date.getTime()
	}
	_format(format = 'yyyy-MM-dd HH:mm.ss.SSS') {
		this._text = format
			.replace(/y+/gi, text(this._year))
			.replace(/M+/g, text(this._month))
			.replace(/d+/gi, text(this._day))
			.replace(/H+/g, text(this._hour))
			.replace(/h+/g, text(this._hour >= 12 ? this._hour - 12 : this._hour))
			.replace(/m+/g, text(this._minute))
			.replace(/s+/g, text(this._second))
			.replace(/S+/g, text(this._sss, 3))
			.replace(/e+/gi, text(this._week))
	}

	get timestamp(): number {
		return this._timestamp
	}

	get date(): Date {
		return this._date
	}

	get week(): number {
		return this._week
	}

	get sss(): number {
		return this._sss
	}

	get second(): number {
		return this._second
	}

	get minute(): number {
		return this._minute
	}

	get hour(): number {
		return this._hour
	}

	get day(): number {
		return this._day
	}

	get month(): number {
		return this._month
	}

	get year(): number {
		return this._year
	}

	get text(): string {
		return this._text
	}
}

interface TimeCountType {
	o?: NodeJS.Timer | null
	time?: number
	isStart?: boolean
	isFinish?: boolean
	isInProgress?: boolean
	isCountdown?: boolean
	step?: number
	finishMethod?: () => void
}

const TIME_COUNT_DEFAULT_VALUE: TimeCountType = {
	o: null,
	time: 0,
	isStart: false,
	isFinish: false,
	isInProgress: false,
	isCountdown: false,
	step: 1
}

/**
 * 计时工具
 */
export class TimeCountModel implements TimeCountType {
	o?: NodeJS.Timer | null
	time: number
	isStart?: boolean
	isFinish?: boolean
	isInProgress?: boolean
	isCountdown?: boolean
	step?: number

	finishMethod?: () => void

	constructor(value: TimeCountType) {
		this.isCountdown = value.isCountdown || TIME_COUNT_DEFAULT_VALUE.isCountdown
		this.isFinish = value.isFinish || TIME_COUNT_DEFAULT_VALUE.isFinish
		this.isInProgress = value.isInProgress || TIME_COUNT_DEFAULT_VALUE.isInProgress
		this.isStart = value.isStart || TIME_COUNT_DEFAULT_VALUE.isStart
		this.o = value.o || TIME_COUNT_DEFAULT_VALUE.o
		this.step = value.step || TIME_COUNT_DEFAULT_VALUE.step
		this.time = value.time || TIME_COUNT_DEFAULT_VALUE.time || 0
		this.finishMethod = value.finishMethod || TIME_COUNT_DEFAULT_VALUE.finishMethod
		this.init()
	}

	/**
	 * 初始化
	 */
	init() {
		// 如果是倒计时。将默认事件设置为60
		this.time = this.isCountdown ? (this.time > 0 ? this.time : 60) : this.time
	}

	/**
	 * 开始计时
	 * @returns {TimeCountModel}
	 */
	start() {
		if (!this.isStart || !this.isInProgress) {
			this.o = setInterval(() => {
				if (this.isCountdown) {
					this.time--
					// 如果倒计时等于0则自动停止
					if (this.time < 0) {
						this.finish()
						this.time = 0
					}
				} else {
					this.time++
				}
			}, 1000)
			this.isStart = true
			this.isInProgress = true
			this.isFinish = false
		} else {
			throw new Error('计时已经开始，请先结束计时')
		}
		return this
	}

	/**
	 * 结束计时
	 * @returns {TimeCountModel}
	 */
	finish() {
		if (this.o && this.isStart && this.isInProgress && !this.isFinish) {
			clearInterval(this.o)
			this.isStart = true
			this.isFinish = true
			this.isInProgress = false
			if (this.finishMethod) {
				this.finishMethod()
			}
		} else {
			throw new Error('计时结束错误')
		}
		return this
	}
}
